package com.liang.ali.paint;

import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDManager;
import ai.djl.ndarray.index.NDIndex;
import ai.djl.ndarray.types.DataType;
import ai.djl.ndarray.types.Shape;
import ai.djl.nn.Activation;
import ai.djl.pytorch.engine.PtNDArray;
import ai.djl.pytorch.jni.JniUtils;
import com.liang.ali.paint.entity.FloatObject;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import net.coobird.thumbnailator.Thumbnails;
import org.tensorflow.framework.TensorProto;
import org.tensorflow.framework.TensorShapeProto;
import tensorflow.serving.Model;
import tensorflow.serving.Predict;
import tensorflow.serving.PredictionServiceGrpc;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.FileInputStream;
import java.nio.file.Paths;
import java.util.List;
import java.util.*;

import static org.tensorflow.framework.DataType.DT_FLOAT;


/*
 * @Author iLy
 * @Description
 * @ClassName test
 * @Date 2021/11/1 14:43
 * @VERSION 1.0
 **/
public class RePaint {

    public List<FloatObject> receiveCap(String fileName) throws Exception {
        //String canvasPhotoBase64Data = "";

        //String file = base64ToFile(canvasPhotoBase64Data, "test.jpg").toString();
        //String file = "D:\\image\\0244.jpg";
        String file = fileName;
        //读取文件，强制修改图片大小，设置输出文件格式bmp(模型定义时输入数据是无编码的)
        BufferedImage im = Thumbnails.of(file).forceSize(512, 512).outputFormat("bmp").asBufferedImage();
        //转换图片到图片数组，匹配输入数据类型为Float
        Raster raster = im.getData();
        List<Float> floatList = new ArrayList<>();
        float[] temp = new float[raster.getWidth() * raster.getHeight() * raster.getNumBands()];
        float[] pixels = raster.getPixels(0, 0, raster.getWidth(), raster.getHeight(), temp);
        for (float pixel : pixels) {
            floatList.add(pixel/255);
        }

        //#记个时
        long t = System.currentTimeMillis();
        //创建连接，注意usePlaintext设置为true表示用非SSL连接
        ManagedChannel channel = ManagedChannelBuilder.forAddress("121.196.146.141", 8500).usePlaintext(true).build();
        //这里还是先用block模式
        PredictionServiceGrpc.PredictionServiceBlockingStub stub = PredictionServiceGrpc.newBlockingStub(channel);
        //创建请求
        Predict.PredictRequest.Builder predictRequestBuilder = Predict.PredictRequest.newBuilder();
        //模型名称和模型方法名预设
        Model.ModelSpec.Builder modelSpecBuilder = Model.ModelSpec.newBuilder();
        modelSpecBuilder.setName("simple_test");
        modelSpecBuilder.setSignatureName("serving_default");
        predictRequestBuilder.setModelSpec(modelSpecBuilder);
        //设置入参,访问默认是最新版本，如果需要特定版本可以使用tensorProtoBuilder.setVersionNumber方法
        TensorProto.Builder tensorProtoBuilder = TensorProto.newBuilder();
        tensorProtoBuilder.setDtype(DT_FLOAT);
        TensorShapeProto.Builder tensorShapeBuilder = TensorShapeProto.newBuilder();
        tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(1));
        //#150528 = 224 * 224 * 3
        tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(512));
        tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(512));
        tensorShapeBuilder.addDim(TensorShapeProto.Dim.newBuilder().setSize(3));
        tensorProtoBuilder.setTensorShape(tensorShapeBuilder.build());
        tensorProtoBuilder.addAllFloatVal(floatList);
        predictRequestBuilder.putInputs("input_1", tensorProtoBuilder.build());
        //访问并获取结果
        Predict.PredictResponse predictResponse = stub.predict(predictRequestBuilder.build());

        Map<String, TensorProto> outputsMap = predictResponse.getOutputsMap();
        TensorProto conv2d_1011 = outputsMap.get("conv2d_101");
        TensorProto conv2d_1099 = outputsMap.get("conv2d_109");
        TensorProto conv2d_933 = outputsMap.get("conv2d_93");

        NDArray conv2d109ND = extracted(conv2d_1099);
        NDArray conv2d101ND = extracted(conv2d_1011);
        NDArray conv2d93ND = extracted(conv2d_933);

        float[][][][] conv2d109List = extracted1(conv2d_1099);
        float[][][][] conv2d101List = extracted1(conv2d_1011);
        float[][][][] conv2d93List = extracted1(conv2d_933);


        List<Float> conv2d_109 = predictResponse.getOutputsMap().get("conv2d_109").getFloatValList();
        List<Float> conv2d_101 = predictResponse.getOutputsMap().get("conv2d_101").getFloatValList();
        List<Float> conv2d_93 = predictResponse.getOutputsMap().get("conv2d_93").getFloatValList();

        List<FloatObject> decode = decode(conv2d109List, conv2d101List, conv2d93List, conv2d109ND, conv2d101ND, conv2d93ND, file);
        return decode;
    }

    public List<FloatObject> decode(float[][][][] conv2d_109,float[][][][] conv2d_101,float[][][][] conv2d_93 ,NDArray conv2d109ND, NDArray conv2d101ND, NDArray conv2d93ND, String file) throws Exception {
        List<String> classes = Arrays.asList("can", "bottle", "branch", "hay", "small-white", "grass",
                "leaf", "plastic-bag", "cup", "ship", "person", "the-nets", "water-float", "flower",
                "lotus-leaf", "paper", "black-floaters", "milk-box", "bubble", "bigunknow", "float1",
                "float2", "distance", "ball");
        float[][] anchors = new float[][]{{12, 16}, {19, 36}, {40, 28}, {36, 75}, {76, 55},
                {72, 146}, {142, 110}, {192, 243}, {459, 401}};

        int[] inputShape = new int[]{416,416};
        int classesNum = classes.size();
        // 加载动态库
        // 加载动态库
//        URL url = ClassLoader.getSystemResource("lib.opencv/opencv_java454.dll");
//        System.load(url.getPath());

        List<Color> preColors = new ArrayList<>();
        for (int i = 0; i < classesNum; i++) {
            float i1 = i*1.0000f / classesNum;

            Random random = new Random();
            float hue = random.nextFloat();
            // sat between 0.1 and 0.3。
            //saturation变量表示颜色的饱和度，取值为0-1之间的浮点值。
            //这里设置为0.1-0.3范围之间。
            float saturation = (random.nextInt(2000) + 1000) / 10000f;
            //luminance变量表示颜色的亮度，取值也是0-1之间的浮点值。
            //这里取值为0.9。
            float luminance = 0.9f;
            //getHSBColor函数创建一个基于hsb颜色模型的color对象。
            //Color color1 = Color.getHSBColor(hue, saturation, luminance);
            Color color1 =  Color.getHSBColor(i1, new Random().nextFloat(), new Random().nextFloat());

            preColors.add(color1);
        }

        List<Color> colors = new ArrayList<>();
        for (Color preColor : preColors) {
            int green = preColor.getGreen();
            int blue = preColor.getBlue();
            int red = preColor.getRed();
            Color color = new Color(green, blue, red);
            colors.add(color);
        }

        //Random random = new Random(10101);
        Collections.shuffle(colors);
        float score = 0.5f;
        float iou = 0.3f;


        Image imgArr = ImageFactory.getInstance().fromFile(Paths.get(file));
        int height = imgArr.getHeight();
        int width = imgArr.getWidth();

        double[] model_image_size = new double[]{height,width};

        BufferedImage image = ImageIO.read(new FileInputStream(file));

        int numLayers = 3;

        List<NDArray> feat = new ArrayList<>();
        feat.add(conv2d109ND);
        feat.add(conv2d101ND);
        feat.add(conv2d93ND);

        List<float[][][][]> featList = new ArrayList<>();
        featList.add(conv2d_109);
        featList.add(conv2d_101);
        featList.add(conv2d_93);

        NDManager ndManager = NDManager.newBaseManager();

        //inputShape ModelImageSize
        NDArray inputShapeRe = ndManager.create(inputShape);
        NDArray ModelImageSize = ndManager.create(model_image_size);
        NDArray anchorsRe = ndManager.create(anchors);

        // 特征层1对应的anchor是678
        // 特征层2对应的anchor是345
        // 特征层3对应的anchor是012
        int[][] anchor_mask = new int[][]{{6, 7, 8},{3, 4, 5}, {0, 1, 2}};

        //boxes boxScores
        NDArray boxes = null;
        NDArray boxScores = null;
        List<NDArray> boxesList = new ArrayList<>();
        List<NDArray> boxScoresList = new ArrayList<>();

        for (int i = 0; i < numLayers; i++) {
            int[] masks = anchor_mask[i];
            List<float[]> anchor1 = new ArrayList<>();
            for (int i1 = 0; i1 < masks.length; i1++) {
                anchor1.add(anchors[masks[i1]]);
            }
            Map<String, NDArray> stringNDArrayMap = yoloBoxesAndScores(featList.get(i), feat.get(i), anchor1, classesNum, inputShapeRe, ModelImageSize);
            //boxesRe
            //boxScoresRe
            NDArray boxesRe = stringNDArrayMap.get("boxesRe");
            NDArray boxScoresRe = stringNDArrayMap.get("boxScoresRe");

            boxesList.add(boxesRe);
            boxScoresList.add(boxScoresRe);
        }
        boxes = boxesList.get(0);
        boxScores = boxScoresList.get(0);
        for (int i = 1; i < boxesList.size(); i++) {
            boxes = boxes.concat(boxesList.get(i));
            boxScores = boxScores.concat(boxScoresList.get(i));
        }
        NDArray ndArray = boxes.toType(DataType.FLOAT32, true);
        float[] boxes1 = ndArray.toFloatArray();
        NDArray ndArray1 = boxScores.toType(DataType.FLOAT32, true);
        float[] boxScores1 = ndArray1.toFloatArray();
        //mask
        NDArray mask = boxScores.gt(score);
        boolean[] floats1 = mask.toBooleanArray();

        List<Float> boxScoreList = new ArrayList<>();
        List<float[]> boxList = new ArrayList<>();
        List<Integer> classList = new ArrayList<>();

        List<Integer> classResult = new ArrayList<>();
        List<float[]> boxResult = new ArrayList<>();
        List<Float> scoreResult = new ArrayList<>();

        long size1 = mask.size(0);
        for (long i = 0; i < size1; i++) {
            boolean[] booleans1 = mask.get(i).toBooleanArray();
            for (int l = 0; l < booleans1.length; l++) {
                if (booleans1[l]){
                    classList.add(l);
                    NDArray ndArray4 = boxes.get(i);
                    NDArray ndArray2 = ndArray4.toType(DataType.FLOAT32,true);
                    float[] floats = ndArray2.toFloatArray();
                    boxList.add(floats);
                    //score
                    NDArray ndArray3 = boxScores.get(i);
                    NDArray ndArray5 = ndArray3.toType(DataType.FLOAT32, true);
                    float[] floats2 = ndArray5.toFloatArray();
                    for (float aFloat : floats2) {
                        if (aFloat < 0.5){
                            continue;
                        }else {
                            boxScoreList.add(aFloat);

                        }
                    }
                }
            }
        }

        for (int i = 0; i < classesNum; i++) {
            List<float[]> boxMap = new ArrayList<>();
            List<Float> scoreMap = new ArrayList<>();
            for (int i1 = 0; i1 < classList.size(); i1++) {
                if (classList.get(i1) == i){
                    boxMap.add(boxList.get(i1));
                    scoreMap.add(boxScoreList.get(i1));
                }
            }
            if (boxMap.size() > 0){
                List<Integer> list = single_class_non_max_suppression(boxMap, scoreMap, 0.5f, boxMap.size(), iou);
                for (Integer in : list) {
                    classResult.add(i);
                    boxResult.add(boxMap.get(in));
                    scoreResult.add(scoreMap.get(in));
                }
            }
        }

        Integer[] classArray = classResult.toArray(new Integer[classResult.size()]);
        float[][] boxArray = boxResult.toArray(new float[boxResult.size()][]);
        Float[] scoreArray = scoreResult.toArray(new Float[scoreResult.size()]);
        PainImage.painImage(file, classArray, scoreArray, boxArray);

        List<FloatObject> objects = new ArrayList<>();
        for (int i = 0; i < classResult.size(); i++) {
            FloatObject floatObject = new FloatObject(scoreResult.get(i), classResult.get(i), boxResult.get(i));
            objects.add(floatObject);
        }
        return objects;
    }

    public List<Integer> single_class_non_max_suppression(List<float[]> bboxes, List<Float> confidences, float CONF_THRESH, int NUM_DETECTIONS, float IOU_THRESH) {
        if (bboxes.size() == 0)
            return null;
        List<Integer> conf_keep_idx = new ArrayList<>();//保存置信度大于CONF_THRESH的元素的下标
        List<Float> new_confidences = new ArrayList<>();//保存置信度大于CONF_THRESH的元素的值
        for (int i = 0; i < confidences.size(); i++) {
            float confidence = confidences.get(i);
            if (confidence > CONF_THRESH){
                conf_keep_idx.add(i);
                new_confidences.add(confidence);
            }
        }
        if (conf_keep_idx.isEmpty())
            return null;

        int alive_idx_size = conf_keep_idx.size();

        List<Idxs> idxsList = new ArrayList<>();//将置信度与下标对应
        for (int i = 0; i < alive_idx_size; i++) {
            Idxs idxs = new Idxs(conf_keep_idx.get(i), new_confidences.get(i));
            idxsList.add(idxs);
        }
        //按score升序排列
        Collections.sort(idxsList, new Comparator<Idxs>() {
            @Override
            public int compare(Idxs o1, Idxs o2) {
                return (int)(o1.getProbability()*10 - o2.getProbability()*10);
            }
        });

        float overlap_xmin, overlap_ymin, overlap_xmax, overlap_ymax;
        float overlap_w, overlap_h, overlap_area, overlap_ratio;
        //取出得分最高的bbox，计算剩下的bbox与它的交并比iou，去掉大于iou_thresh的bbox
        List<Integer> pickList = new ArrayList<>();
        while (idxsList.size() > 0) {
            int last = idxsList.size() - 1;
            if(pickList.size() >= NUM_DETECTIONS)//取置信度最高的NUM_DETECTIONS个结果
                break;
            int last_index = idxsList.get(last).getIndex();
            float last_area = (bboxes.get(last_index)[2] - bboxes.get(last_index)[0]) * (bboxes.get(last_index)[3] - bboxes.get(last_index)[1]);//area=(xmax-xmin)*(ymax-ymin)
            pickList.add(last_index);
            List<Idxs> idxs_to_remove = new ArrayList<>();//交并比过大需要移除的bbox
            for (int i = 0; i < last; i++) {
                int i_index = idxsList.get(i).getIndex();
                overlap_xmin = Math.max(bboxes.get(last_index)[0], bboxes.get(i_index)[0]);
                overlap_ymin = Math.max(bboxes.get(last_index)[1], bboxes.get(i_index)[1]);
                overlap_xmax = Math.min(bboxes.get(last_index)[2], bboxes.get(i_index)[2]);
                overlap_ymax = Math.min(bboxes.get(last_index)[3], bboxes.get(i_index)[3]);
                overlap_w = Math.max(0, overlap_xmax - overlap_xmin);
                overlap_h = Math.max(0, overlap_ymax - overlap_ymin);
                overlap_area = overlap_w * overlap_h;
                float i_area = (bboxes.get(i_index)[2] - bboxes.get(i_index)[0]) * (bboxes.get(i_index)[3] - bboxes.get(i_index)[1]);
                overlap_ratio = overlap_area / ( last_area + i_area - overlap_area);//IOU
                if (overlap_ratio > IOU_THRESH)
                    idxs_to_remove.add(idxsList.get(i));
            }
            idxs_to_remove.add(idxsList.get(last));
            idxsList.removeAll(idxs_to_remove);
        }
        return pickList;
    }


    public Map<String, NDArray> yoloBoxesAndScores(float[][][][] featList, NDArray feats, List<float[]> anchors, int num_classes, NDArray input_shape, NDArray image_shape){
        Map<String, NDArray> ptNDArrayMap = yoloHead(featList, feats, anchors, num_classes, input_shape);
        NDArray boxes = yoloCorrectBoxes(ptNDArrayMap, input_shape, image_shape);

        //boxConfidence  boxClassProbs
        NDArray boxConfidence = ptNDArrayMap.get("boxConfidence");
        NDArray boxClassProbs = ptNDArrayMap.get("boxClassProbs");

        NDArray boxesRe = boxes.reshape(new Shape(-1, 4));

        //boxScores
        NDArray boxScores = boxConfidence.mul(boxClassProbs);
        NDArray boxScoresRe = boxScores.reshape(new Shape(-1, num_classes));

        Map<String, NDArray> result = new HashMap<>();
        result.put("boxesRe", boxesRe);
        result.put("boxScoresRe", boxScoresRe);

        return result;
    }

    public  Map<String, NDArray> yoloHead(float[][][][] featList, NDArray  feats, List<float[]> anchors, int num_classes, NDArray input_shape){

        int anchorSize = anchors.size();
        float[] anchors1 = new float[anchorSize*anchors.get(1).length];

        for (int i = 0; i < anchorSize; i++) {
            System.arraycopy(anchors.get(i),0,anchors1,i*(anchors.get(i).length),anchors.get(i).length);
        }

        float[][][][][] anchors_tensor = new float[1][1][1][anchorSize][2];
        int k = 0;
        for (int i = 0; i < anchors_tensor.length; i++) {
            for (int i1 = 0; i1 < anchors_tensor[i].length; i1++) {
                for (int i2 = 0; i2 < anchors_tensor[i][i1].length; i2++) {
                    for (int i3 = 0; i3 < anchors_tensor[i][i1][i2].length; i3++) {
                        for (int i4 = 0; i4 < anchors_tensor[i][i1][i2][i3].length;i4++) {

                            anchors_tensor[i][i1][i2][i3][i4] = anchors1[k];
                            k++;

                        }
                    }
                }
            }
        }

        Shape shape = feats.getShape();
        long l = shape.get(1);
        long l1 = shape.get(2);
        //grid_shape
        long[] gridShape = new long[]{l,l1};
        NDManager ndManager = NDManager.newBaseManager();

        //grid_y
        NDArray arangeY = ndManager.arange(gridShape[0]);
        NDArray reshapeY = arangeY.reshape(new Shape(-1, 1, 1, 1));


        long[] repeatsY = new long[]{1, gridShape[1], 1, 1};
        NDArray gridY = reshapeY.tile(repeatsY);

        //grid_x
        NDArray arangeX = ndManager.arange(gridShape[1]);
        NDArray reshapeX = arangeX.reshape(new Shape(1, -1, 1, 1));
        long[] repeatsX = new long[]{gridShape[0], 1, 1, 1};
        NDArray gridX = reshapeX.tile(repeatsX);
        //grid
        NDArray grid = gridX.concat(gridY,3);

        //feats
        NDArray featsReshape = feats.reshape(new Shape(-1, gridShape[0], gridShape[1], anchorSize, num_classes + 5));

        //gridShape inputShape anchors_tensorRe
        NDArray anchors_tensorRe = ndManager.create(new Shape(1, 1, 1, anchorSize, 2));
        anchors_tensorRe.set(anchors1);
        NDArray gridShapeRe = ndManager.create(gridShape);

        //box_xy
        NDArray sigmoid = Activation.sigmoid(featsReshape.get(new NDIndex(":, :, :, :, :2")));
        NDArray add = sigmoid.add(grid);
        NDArray boxXy = add.div(gridShapeRe.get(new NDIndex("-1")));

        //box_wh
        NDArray exp = featsReshape.get(new NDIndex(":, :, :, :, 2:4")).exp();
        NDArray mul = exp.mul(anchors_tensorRe);
        NDArray boxWh = mul.divi(input_shape.toType(featsReshape.getDataType(),true));

        //box_confidence
        PtNDArray boxConfidence = JniUtils.sigmoid((PtNDArray) featsReshape.get(new NDIndex(":, :, :, :, 4:5")));

        //box_class_probs
        PtNDArray boxClassProbs = JniUtils.sigmoid((PtNDArray) featsReshape.get(new NDIndex(":, :, :, :, 5:")));

        Map<String, NDArray> result = new HashMap<>();
        result.put("boxXy", boxXy);
        result.put("boxWh", boxWh);
        result.put("boxConfidence", boxConfidence);
        result.put("boxClassProbs", boxClassProbs);

        return result;
    }

    public NDArray yoloCorrectBoxes( Map<String, NDArray> ptNDArraysMap, NDArray input_shape, NDArray image_shape){

        //boxXy  boxWh  boxConfidence  boxClassProbs
        NDArray boxXy = ptNDArraysMap.get("boxXy");
        NDArray boxWh = ptNDArraysMap.get("boxWh");

        //boxYx  boxHw
        NDArray boxYx = boxXy.flip(4);
        NDArray boxHw = boxWh.flip(4);

        //newShape
        NDArray min = input_shape.div(image_shape).min();
        NDArray mul = image_shape.mul(min);
        NDArray newShape = mul.round();

        //offset
        NDArray sub = input_shape.sub(newShape);
        NDArray div = sub.div(2.);
        NDArray offset = div.div(input_shape);

        //scale
        NDArray scale = input_shape.div(newShape);

        //boxYxRe
        NDArray sub1 = boxYx.sub(offset);
        NDArray boxYxRe = sub1.mul(scale);

        //boxHwRe
        NDArray boxHwRe = boxHw.mul(scale);

        //boxMins
        NDArray div1 = boxHwRe.div(2.0);
        NDArray boxMins = boxYxRe.sub(div1);

        //boxMaxes
        NDArray div2 = boxHwRe.div(2.0);
        NDArray boxMaxes = boxYxRe.add(div2);
        //boxes
        NDArray boxes = boxMins.concat(boxMaxes,4);
        //boxesRe
        NDArray imageShapeCon = image_shape.concat(image_shape);
        NDArray boxesRe = boxes.mul(imageShapeCon);

        return boxesRe;
    }

    private float[][][][] extracted1(TensorProto conv2d_1011) {
        List<Float> conv2d_101 = conv2d_1011.getFloatValList();
        TensorShapeProto conv2d_1011Shape = conv2d_1011.getTensorShape();
        List<TensorShapeProto.Dim> conv2d_1011DimList = conv2d_1011Shape.getDimList();

        float[] conv2dArray = new float[conv2d_101.size()];
        for (int i = 0; i < conv2dArray.length; i++) {
            conv2dArray[i] = conv2d_101.get(i);
        }

        int dim1 = (int)conv2d_1011DimList.get(0).getSize();
        int dim2 = (int)conv2d_1011DimList.get(1).getSize();
        int dim3 = (int)conv2d_1011DimList.get(2).getSize();
        int dim4 = (int)conv2d_1011DimList.get(3).getSize();

        float[][][][] reshape = new float[dim1][dim2][dim3][dim4];
        int index = 0;
        for (int i = 0; i < dim1; i++) {
            for (int i1 = 0; i1 < dim2; i1++) {
                for (int i2 = 0; i2 < dim3; i2++) {
                    for (int i3 = 0; i3 < dim4; i3++) {
                        reshape[i][i1][i2][i3] = conv2dArray[index];
                        index++;
                    }
                }
            }
        }
        return reshape;
    }

    private NDArray extracted(TensorProto conv2d_1011) {
        List<Float> conv2d_101 = conv2d_1011.getFloatValList();
        TensorShapeProto conv2d_1011Shape = conv2d_1011.getTensorShape();
        List<TensorShapeProto.Dim> conv2d_1011DimList = conv2d_1011Shape.getDimList();

        float[] conv2dArray = new float[conv2d_101.size()];
        for (int i = 0; i < conv2dArray.length; i++) {
            conv2dArray[i] = conv2d_101.get(i);
        }


        int dim1 = (int)conv2d_1011DimList.get(0).getSize();
        int dim2 = (int)conv2d_1011DimList.get(1).getSize();
        int dim3 = (int)conv2d_1011DimList.get(2).getSize();
        int dim4 = (int)conv2d_1011DimList.get(3).getSize();

        NDManager ndManager = NDManager.newBaseManager();
        NDArray reshape = ndManager.create(conv2dArray, new Shape(dim1, dim2, dim3, dim4));
        return reshape;
    }

//    public File base64ToFile(String base64, String fileName) {
//        File file = null;
//        //创建文件目录
//        String filePath = "D:\\image";
//        File dir = new File(filePath);
//        if (!dir.exists() && !dir.isDirectory()) {
//            dir.mkdirs();
//        }
//        BufferedOutputStream bos = null;
//        FileOutputStream fos = null;
//        try {
//            byte[] bytes = Base64.getDecoder().decode(base64.split(",")[1]);
//            file = new File(filePath + "\\" + fileName);
//            fos = new FileOutputStream(file);
//            bos = new BufferedOutputStream(fos);
//            bos.write(bytes);
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            if (bos != null) {
//                try {
//                    bos.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//            if (fos != null) {
//                try {
//                    fos.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//        return file;
//    }
//
//    public Color HSVtoRGB(float h, float s, float v) {
//        float f, p, q, t;
//        if (s == 0) {// achromatic (grey)
//            return new Color(v, v, v);
//        }
//        h /= 60;// sector 0 to 5
//        int i = (int) Math.floor(h);
//        f = h - i; // factorial part of h
//        p = v * (1 - s);
//        q = v * (1 - s * f);
//        t = v * (1 - s * (1 - f));
//        switch (i) {
//            case 0:
//                return new Color(v, t, p);
//            case 1:
//                return new Color(q, v, p);
//            case 2:
//                return new Color(p, v, t);
//            case 3:
//                return new Color(p, q, v);
//            case 4:
//                return new Color(t, p, v);
//            default: // case 5:
//                return new Color(v,p,q); } }

}



